import { Binary, ObjectId } from 'mongodb'
import * as db from '../db'
import * as crypto from 'crypto'
import { IArticle } from '../types'
import { stats } from '../stats'
import { tokens } from './user.service'
import * as fs from 'fs'

// 查看是否已赞
export async function findLike(articleId: string, token: string) {
  const id = tokens.get(token)
  const myuser = await db.userCollection.findOne({
    _id: new ObjectId(id)
  })
  if (myuser === undefined) throw stats.ERR_NOT_LOGIN
  const res = await db.likeCollection.findOne({
    userId: new ObjectId(id),
    articleId: new ObjectId(articleId)
  })
  if (res === undefined) {
    return false
  } else {
    return true
  }
}

// 点赞，取消赞
export async function like(
  state: boolean,
  articleId: string,
  articleName: string,
  token: string
) {
  const id = tokens.get(token)
  const myuser = await db.userCollection.findOne({
    _id: new ObjectId(id)
  })
  if (myuser === undefined) throw stats.ERR_NOT_LOGIN
  const article = await db.articleCollection.findOne({
    _id: new ObjectId(articleId)
  })
  if (state === true) {
    await db.likeCollection.findOneAndDelete({
      userId: new ObjectId(id),
      articleId: new ObjectId(articleId)
    })
    await db.articleCollection.findOneAndUpdate(
      {
        _id: new ObjectId(articleId)
      },
      {
        $set: {
          likes: article.likes - 1
        }
      }
    )
  } else {
    await db.likeCollection.insertOne({
      userId: new ObjectId(id),
      time: new Date(),
      articleId: new ObjectId(articleId),
      title: articleName
    })
    await db.articleCollection.findOneAndUpdate(
      {
        _id: new ObjectId(articleId)
      },
      {
        $set: {
          likes: article.likes + 1
        }
      }
    )
  }
  return 'ok'
}

// 评论
export async function comment(
  articleId: string,
  token: string,
  content: string
) {
  const id = tokens.get(token)
  const myuser = await db.userCollection.findOne({
    _id: new ObjectId(id)
  })
  if (myuser === undefined) throw stats.ERR_NOT_LOGIN

  await db.commentCollection.insertOne({
    userId: new ObjectId(id),
    time: new Date(),
    articleId: new ObjectId(articleId),
    content: content
  })
  return 'ok'
}

// 浏览
export async function view(articleId: string) {
  const res = await db.articleCollection.findOne({
    _id: new ObjectId(articleId)
  })
  if (res === undefined) throw stats.ERR_NOT_FOUND
  await db.articleCollection.findOneAndUpdate(
    {
      _id: new ObjectId(articleId)
    },
    {
      $set: {
        views: res.views + 1
      }
    }
  )
  return 'ok'
}

// 删除评论
export async function removeComment(id: string) {
  await db.commentCollection.findOneAndDelete({
    _id: new ObjectId(id)
  })
  return 'ok'
}

// 发布文章
export async function post(article: IArticle, token: string) {
  const id = tokens.get(token)
  const myuser = await db.userCollection.findOne({
    _id: new ObjectId(id)
  })
  if (myuser === undefined) throw stats.ERR_NOT_LOGIN
  await db.articleCollection.insertOne({
    title: article.title,
    content: article.content,
    author: new ObjectId(id),
    time: new Date(),
    banner: article.banner,
    label: article.label,
    views: 0,
    likes: 0
  })
  return 'ok'
}

// 编辑文章
export async function edit(id: string, article: IArticle, token: string) {
  const id1 = tokens.get(token)
  const myuser = await db.userCollection.findOne({
    _id: new ObjectId(id1)
  })
  if (myuser === undefined) throw stats.ERR_NOT_LOGIN
  await db.articleCollection.findOneAndUpdate(
    {
      _id: new ObjectId(id)
    },
    {
      $set: {
        time: new Date(),
        label: article.label,
        content: article.content,
        title: article.title,
        banner: article.banner
      }
    }
  )
  return 'ok'
}

// 删除文章
export async function remove(_id: string, token: string) {
  const id = tokens.get(token)
  const myuser = await db.userCollection.findOne({
    _id: new ObjectId(id)
  })
  if (myuser === undefined) throw stats.ERR_NOT_LOGIN
  await db.articleCollection.findOneAndDelete({
    _id: new ObjectId(_id)
  })
  const rows = await db.commentCollection
    .find({
      articleId: new ObjectId(_id)
    })
    .toArray()
  rows.map(async item => {
    await db.commentCollection.findOneAndDelete({
      _id: item._id
    })
  })
  await db.likeCollection.findOneAndDelete({
    articleId: new ObjectId(_id)
  })
  return 'ok'
}

// 搜索文章
export async function search(str: string) {
  const res = await db.articleCollection
    .aggregate([
      {
        $match: { title: { $regex: str, $options: 'i' } }
      },
      {
        $lookup: {
          from: 'user',
          localField: 'author',
          foreignField: '_id',
          as: 'user'
        }
      }
    ])
    .toArray()
  const res2 = await db.articleCollection.find({
    label: { $elemMatch: { $regex: str, $options: 'i' } }
  }).toArray()
  res.concat(res2)
  return res
}

// 文章详情
export async function detail(id: string) {
  const res = await db.articleCollection
    .aggregate([
      {
        $match: { _id: new ObjectId(id) }
      },
      {
        $lookup: {
          from: 'user',
          localField: 'author',
          foreignField: '_id',
          as: 'user'
        }
      }
    ])
    .toArray()
  return res
}

// 文章评论列表
export async function comments(articleId: string) {
  const res = await db.commentCollection
    .aggregate([
      {
        $match: { articleId: new ObjectId(articleId) }
      },
      {
        $lookup: {
          from: 'user',
          localField: 'userId',
          foreignField: '_id',
          as: 'user'
        }
      }
    ])
    .toArray()
  return res
}

// 文件上传
export async function upload(path: string, size: number, name: string) {
  const key = crypto.randomBytes(16).toString('hex')
  const data = await fs.promises.readFile(path)
  await db.fileCollection.insertOne({
    key: key,
    data: new Binary(data),
    size: size,
    name: name
  })
  await fs.promises.unlink(path)
  return key
}

/**
 * 查找文件
 * @param key
 * @returns
 */
export async function download(key: string) {
  const result = await db.fileCollection.findOne({
    key: key
  })
  if (!result) throw stats.ERR_NOT_FOUND
  return result
}
